#include "types.h"
#include <cassert>

namespace stdf {

    CN::CN(void)
    {
        _str = "";
    }

    CN& CN::operator= (string s)
    {
        assert(s.size() < 256);

        _str = s;
        return *this;
    }

    void CN::set(string s)
    {
        assert(s.size() < 256);
        _str = s;
    }

    U2 CN::getLength(void)
    {
        U2 len = 1 + _str.length();
        return len;
    }

    bool CN::isValid(void) {
        if(_str.length() == 0)
            return false;
        else
            return true;
    }

    /*
    U2 CN::operator+ (U2 num) {
        U2 len;
        len = num + _str.length();
        return len;
    }
    */

    ostream& operator<<(ostream& os, CN& cn)
    {
#ifdef DEBUG
        os << "[" << (int) cn.getLength() << "] ";
#endif
        os << cn._str;
        return os;
    }

    DN::DN(void)
    {
        count = 0;
        data.clear();
    }

    U2 DN::getLength(void)
    {
        U2 numBytes = 0;
        numBytes += (U2) ((count / 8) + 1);
        if ((count % 8) ==0) numBytes--;
        numBytes += 2;

        return numBytes;
    }

    ostream& operator<<(ostream& os, DN& dn)
    {
#ifdef DEBUG
        os << "[" << (int) dn.count << "] ";
#endif

        std::vector<U1>::iterator iter;

        /*
        os << hex;
        for(iter = dn.data.begin(); iter != dn.data.end(); iter++)
            os << " " << *iter;
        os << endl;
        */
        for (unsigned int i = 0; i < dn.data.size(); i++)
        {
            if (isalnum(dn.data[i]))
                os << " " << dn.data[i];
            else
                os << " " << (int) dn.data[i];
        }
        return os;
    }

    BN::BN(void)
    {
        count = 0;
        data.clear();
    }

    U2 BN::getLength(void)
    {
        U2 len = 1 + count;

        return len;
    }

    BN& BN::operator=(vector<U1> values) {
        assert(values.size() < 256);

        data = values;
        count = data.size();

        return *this;
    }

    ostream& operator<<(ostream& os, BN& bn)
    {
#ifdef DEBUG
        os << "[" << (int) bn.count << "] ";
#endif

        std::vector<U1>::iterator iter;
        for (iter = bn.data.begin(); iter != bn.data.end(); iter++)
            os << hex << *iter;
//        os << toBinString( *iter );
        return os;
    }

    VN::VN(void)
    {
        code = 255;

        r8 = 0;
        u4 = 0; // This will assign all bytes of the union to zero
    }

    U2 VN::getLength(void)
    {
        U2 len = 0;
        len = 1; // code byte

        switch (code)
        {
        case  0: len += 0; break; // B0
        case  1: len += 1; break; // U1
        case  2: len += 2; break; // U2
        case  3: len += 4; break; // U4
        case  4: len += 1; break; // I1
        case  5: len += 2; break; // I2
        case  6: len += 4; break; // I4
        case  7: len += 4; break; // R4
        case  8: len += 8; break; // R8
        case 10: len += cn.getLength(); break; // CN
        case 11: len += bn.getLength(); break; // BN
        case 12: len += dn.getLength(); break; // CN
        case 13: len += 1; break; // N1
        default: break;
        };

        return len;
    }


    ostream& operator<<(ostream& os, VN& gd)
    {
        switch (gd.code)
        {
        case 0:
            os << "PAD";
            break;
        case 1:
            os << (int) gd.u1;
            break;
        case 2:
            os << (int) gd.u2;
            break;
        case 3:
            os << (int) gd.u4;
            break;
        case 4:
            os << (int) gd.i1;
            break;
        case 5:
            os << (int) gd.i2;
            break;
        case 6:
            os << (int) gd.i4;
            break;
        case 7:
            os << gd.r4;
            break;
        case 8:
            os << gd.r8;
            break;
        case 10:
            os << gd.cn;
            break;
        case 11:
            os << gd.bn;
            break;
        case 12:
            os << gd.dn;
            break;
        case 13:
            os << gd.n1;
            break;
        default:
            break;
        };

        return os;
    }

} // end namespace
